package org.hepeng.workx.spring.security.web;

import org.hepeng.workx.exception.ApplicationRuntimeException;
import org.joor.Reflect;
import org.springframework.context.ApplicationContext;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.util.Assert;

import java.util.Objects;

/**
 * @author he peng
 */
public class CustomizeSecurityConfigAttributeSourceConfigurer {

    public static <T extends ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry> T enable(
            T configurer
            , SecurityConfigAttributeLoader securityConfigAttributeLoader) {
        Assert.notNull(configurer , "configurer must not be null");
        Assert.notNull(securityConfigAttributeLoader , "securityConfigAttributeLoader must not be null");
        configurer.withObjectPostProcessor(createSecurityMetadataSourcePostProcessor(Reflect.on(configurer).get("context") , securityConfigAttributeLoader))
                .withObjectPostProcessor(createSecurityExpressionHandlerPostProcessor());

        return configurer;
    }

    public static <T extends ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry> T enable(T configurer) {
        Assert.notNull(configurer , "configurer must not be null");
        if (Objects.isNull(configurer)) {
            throw new NullPointerException(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry.class.getName() + " is null");
        }

        SecurityConfigAttributeLoader securityConfigAttributeLoader = getSecurityConfigAttributeLoaderFromIocContainer(configurer);
        return enable(configurer , securityConfigAttributeLoader);
    }

    private static <T extends ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry> SecurityConfigAttributeLoader getSecurityConfigAttributeLoaderFromIocContainer(T configurer) {
        ApplicationContext context = Reflect.on(configurer).get("context");
        SecurityConfigAttributeLoader securityConfigAttributeLoader = context.getBean(SecurityConfigAttributeLoader.class);
        if (Objects.isNull(securityConfigAttributeLoader)) {
            throw new ApplicationRuntimeException("No instances found from the spring context , Class : " + SecurityConfigAttributeLoader.class);
        }
        return securityConfigAttributeLoader;
    }

    public static ReplaceDefaultSecurityMetadataSourceObjectPostProcessor createSecurityMetadataSourcePostProcessor(ApplicationContext context , SecurityConfigAttributeLoader securityConfigAttributeLoader) {

        return new ReplaceDefaultSecurityMetadataSourceObjectPostProcessor(context , securityConfigAttributeLoader);
    }

    public static GlobalSecurityExpressionHandlerCacheObjectPostProcessor createSecurityExpressionHandlerPostProcessor() {
        return new GlobalSecurityExpressionHandlerCacheObjectPostProcessor();
    }
}
